package cn.wizzer.app.crown.modules.services.impl.pl;

import cn.wizzer.app.crown.modules.models.CrownBet;
import cn.wizzer.app.crown.modules.models.CrownMatch;
import cn.wizzer.app.crown.modules.models.constant.CrownConstant;
import cn.wizzer.app.crown.modules.models.constant.CrownPattern;
import cn.wizzer.app.crown.modules.models.enums.BetsEnum;
import cn.wizzer.app.crown.modules.models.vo.CrownXML;
import cn.wizzer.app.crown.modules.models.vo.Game;
import cn.wizzer.app.crown.modules.services.CrownBetService;
import cn.wizzer.app.crown.modules.services.CrownMatchService;
import cn.wizzer.app.crown.modules.services.pl.PdNewestService;
import cn.wizzer.app.sys.modules.services.SysParamService;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.util.DateUtil;
import cn.wizzer.framework.util.Result;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import java.util.List;

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;

@IocBean(args = {"refer:dao"})
@Service(interfaceClass = PdNewestService.class)
public class PdNewestServiceImpl extends BaseServiceImpl<CrownMatch> implements PdNewestService {

    public PdNewestServiceImpl(Dao dao) {
        super(dao);
    }

    private static final Log log = Logs.get();

    @Inject
    private RedisService redisService;
    @Inject
    private CrownMatchService matchService;
    @Inject
    private CrownBetService betService;
    @Reference
    @Inject
    private SysParamService sysParamService;

    /**
     * 投资内容和对应的赔率名称
     */
    private final Map<String, String> betMap = Result.createHashMap(
            "1-0", "Ior_H1C0",
            "2-0", "Ior_H2C0",
            "2-1", "Ior_H2C1",
            "3-0", "Ior_H3C0",
            "3-1", "Ior_H3C1",
            "3-2", "Ior_H3C2",
            "0-0", "Ior_H0C0",
            "1-1", "Ior_H1C1",
            "2-2", "Ior_H2C2",
            "3-3", "Ior_H3C3",
            "0-1", "Ior_H0C1",
            "0-2", "Ior_H0C2",
            "1-2", "Ior_H1C2",
            "0-3", "Ior_H0C3",
            "1-3", "Ior_H1C3",
            "2-3", "Ior_H2C3"
    );

    /**
     * 早盘全场波胆
     *
     * @param crownxml 赛事数据
     * @param dateType 时间类型
     */
    public void handleReceiveData(CrownXML crownxml, String dateType) {
        log.info("新版皇冠全场波胆,dateType:" + dateType + ",receive:" + crownxml);
        for (Game gm : crownxml.getGameList()) {
            // 联赛名称
            String leagueName = gm.getLeague();
            // 过滤掉梦幻赛事
            if ("Fantasy Matches".equals(leagueName)) {
                log.info("过滤掉Fantasy Matches.mid:" + gm.getGid());
                continue;
            }
            CrownMatch match = new CrownMatch();
            // 赛事id
            match.setMid(gm.getGid());
            // 比赛时间
            String year;
            if (CrownConstant.FUTURE.equals(dateType)) {
                year = Calendar.getInstance().getWeekYear() + "-";
            } else {
                year = gm.getSystime().substring(0, 5);
            }
            // "2021-" + "04-30 08:00p" + "m"
            Date dateTime = DateUtil.parseDate( year + gm.getDatetime() + "m", DateUtil.DATE_FORMAT_PATTERN.Y_M_D_H_M_A.PATTERN);
            match.setDateTime(dateTime);
            // 皇冠时间有错误，没有处理美国时间夏令时冬令时。所以自己要处理一下
            this.handleDaylightTime(match);
            // 赛事阶段
            match.setStage(dateType);
            // 联赛名
            match.setLeague(leagueName);
            // 主队名(去掉‘[Mid]’)
            String home = gm.getTeam_h();
            home = CrownPattern.HTML_PATTERN.matcher(home).replaceAll("");
            //中场判断
            if (home.contains("[Mid]")) {
                home = home.replace("[Mid]", "").trim();
                match.setHaveHomeCourt(false);
            } else {
                match.setHaveHomeCourt(true);
            }
            match.setHome(home);

            // 是否有滚球
            if (Strings.isNotBlank(match.getStart()) && match.getStart().contains("running ball")) {
                match.setHaveRoll(true);
            } else {
                match.setHaveRoll(false);
            }

            // 客队名(要去掉HTML标签)
            String custom = gm.getTeam_c();
            custom = CrownPattern.HTML_PATTERN.matcher(custom).replaceAll("");
            match.setCustom(custom);

            // 处理赛事和投资数据
            this.handleMatchAndBets(gm, match);
        }
    }

    /**
     * 赛事、投资数据如果已入库则update，为入库则insert
     *
     * @param gm
     * @param match
     */
    private synchronized void handleMatchAndBets(Game gm, CrownMatch match) {
        // 根据联赛名称，主队名称，客队名称，比赛日期 查询数据是否存在
        CrownMatch old = matchService.queryByTeamInfo(match.getLeague(), match.getHome(), match.getCustom(), match.getDateTime());
        if (old != null) {
            if (CrownConstant.OTHER.equals(old.getStage()) || CrownConstant.FINISHED.equals(old.getStage())) {
                log.info("赛事mid:" + match.getMid() + ",已被手动设置为结束状态，不再更新。任务:全场波胆");
            } else {
                log.info("update赛事,主:" + match.getHome() + ".客:" + match.getCustom() + ".联赛:" + match.getLeague()
                        + ".时间:" + match.getDateTime() + ".mid:" + match.getMid() + ".任务:全场波胆");
                match.setId(old.getId());
                match.setOpAt(Times.getTS());
                match.setProtect(old.getProtect());
                matchService.update(match);
                this.updateBets(gm, match.getId());
            }
        }
        // 插入
        else {
            log.info("首次insert赛事,主:" + match.getHome() + ".客:" + match.getCustom() + ".联赛:" + match.getLeague()
                    + ".时间:" + match.getDateTime() + ".mid:" + match.getMid() + ".任务:全场波胆");
            matchService.insert(match);
            log.info("赛事不存在，hpd初次insert crown_bet。赛事id：" + match.getId() + "。Game：" + gm);
            this.insertBets(gm, match.getId());
        }
    }


    /**
     * 新增Bets方法
     *
     * @param gm
     * @param matchId
     */
    private void insertBets(Game gm, String matchId) {
        List<CrownBet> bets = new ArrayList<>();
        // 获取‘招募金额’
        BigDecimal recruitAmount = sysParamService.fetch().getRecruitAmount();
        // 获取投资内容以及赔率
        for (Map.Entry<String, String> entry : betMap.entrySet()) {
            String key = entry.getKey();
            CrownBet bet = new CrownBet();
            bet.setMatchId(matchId);
            bet.setType(BetsEnum.FULL_PD);
            bet.setRecruitAmount(recruitAmount);
            // 记录波胆比分
            bet.setBetContent(key);
            // 处理赔率
            try {
                bet.setOdds((BigDecimal) gm.getClass().getMethod("get" + entry.getValue()).invoke(gm));
                matchService.handleRate(bet);
                // 加入集合
                bets.add(bet);
            } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                log.error("新版皇冠全场波胆insert Bets反射异常：" + e);
            }
        }
        betService.fastInsert(bets);
        betService.clearCache(matchId, BetsEnum.FULL_PD);
    }

    /**
     * 更新Bets方法
     *
     * @param gm
     * @param matchId
     */
    @Aop(TransAop.REPEATABLE_READ)
    private void updateBets(Game gm, String matchId) {
        int count = betService.count(Cnd.where("matchId", "=", matchId)
                .and("type", "=", BetsEnum.FULL_PD));
        // 更新
        if (count > 0) {
            CrownBet bet = new CrownBet();
            bet.setType(BetsEnum.FULL_PD);
            for (Map.Entry<String, String> entry : betMap.entrySet()) {
                // 转换赔率
                try {
                    bet.setOdds((BigDecimal) gm.getClass().getMethod("get" + entry.getValue()).invoke(gm));
                    matchService.handleRate(bet);
                    // 只更新rateUpdateFlag为true的rate字段(赔率)
                    Chain chain = Chain.make("odds", bet.getOdds()).add("rate", bet.getRate());
                    Cnd cnd = Cnd.where("matchId", "=", matchId)
                            .and("type", "=", BetsEnum.FULL_PD)
                            .and("betContent", "=", entry.getKey())
                            .and("rateUpdateFlag", "=", 1);
                    betService.update(chain, cnd);
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    log.error("新版皇冠全场波胆update Bets反射异常：" + e);
                }
            }
            betService.clearCache(matchId, bet.getType());
        }
        else {
            log.info("赛事已存在，pd初次insert crown_bet。赛事id：" + matchId + "。JSONArray：" + gm);
            this.insertBets(gm, matchId);
        }
    }


    /**
     * 处理美东时间夏令时
     *
     * @param match
     */
    private void handleDaylightTime(CrownMatch match) {
        Calendar cal = Calendar.getInstance();
        Date oldTime = match.getDateTime();
        cal.setTime(oldTime);
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int min = cal.get(Calendar.MINUTE);
        int sec = cal.get(Calendar.SECOND);
        ZonedDateTime now = ZonedDateTime.of(year, month, day, hour, min, sec, 0, ZoneId.of("America/New_York"));
        boolean isDayLight = now.getZone().getRules().isDaylightSavings(now.toInstant());
        // 如果是冬令时时间则date要减一小时
        if (!isDayLight) {
            cal.add(Calendar.HOUR, -1);
            match.setDateTime(cal.getTime());
            log.info("全场波胆，美国冬令时，赛事时间减一小时。赛事mid:" + match.getMid() + "。原赛事时间:" + oldTime
                    + "。修正后的赛事时间:" + match.getDateTime());
        }
    }
}
